#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <time.h>
#include <arpa/inet.h>
#include <poll.h>

#include "socks.h"
#include "tunnet.h"

#include "global.h"
#include "common.h"

#define SLEEPTIME 1000    // 1 second

LOOKUP_ITEM socks4_code[]={
	{ SOCKS4_REP_SUCCEEDED   ,       "Request granted (succeeded) "},
	{ SOCKS4_REP_REJECTED    ,       "Request rejected or failed"}, 
	{ SOCKS4_REP_IDENT_FAIL  ,       "Cannot connect identd"},
	{ SOCKS4_REP_USERID      ,       "User id not matched"},
	{ SOCKS4_REP_HOPS_EXCEED ,       "Max Hops exceed"},
	{ -1, 				 "Unknow" }
};

int WriteSocks5Response(int clntSock, struct socks5_request_pi *request,unsigned char reply_code) ;
void * Service_Socks(void *threadArgs)
{

	int port;
	int version, res;
	int srvSock,clntSock;
	struct sockaddr_storage  srvAddr, clntAddr; // to support IPv6
	struct sockaddr_in  *clnt;
	int addrLength;
	pthread_t socksThreadID;   

        struct pollfd fds; 
	int isset, error;
	char buf[256];


        //int totalThreads;
	totalThreads=0;

	struct ThreadArgs * socksArgs;
	struct service_item *si;

	pthread_detach(pthread_self());

	port = ((struct ThreadArgs *) threadArgs) -> port;
	version = ((struct ThreadArgs *) threadArgs) ->version;

	si=((struct ThreadArgs *) threadArgs) -> p_srvc;

	free(threadArgs);


//Protocol independed, Change the above code to the following ..

	int addrLen;
	char strPort[20];

	sprintf(strPort,"%d", ntohs(port));

	srvSock=tcp_listen(NULL,strPort,&addrLen);

        // add the socket to openSockets array , to close it when interrupted
	openSockets[pointer]=srvSock;
        pointer++;

////////////////////////////////////////
	fds.fd=srvSock;
	fds.events=POLLIN;

	si->status=SRVC_STAT_START;

	sys_log(info_log,"Service SOCKS(%d) started, listening on TCP port %d...\n",version, ntohs(port));
	addrLength=sizeof(clntAddr);
	for(;;){

	    	for(;;){  /// waiting for new connect...
	    		if(si->status==SRVC_STAT_STOP ){
				//cleanup
				close(srvSock);
				return;
	    		}
	    		if(si->status==SRVC_STAT_PAUSE ){
		 		usleep(SLEEPTIME*10);
				continue;
	    		}
	        	isset = (fds.events & POLLIN);
                	if (isset) {
                        	error = poll(&fds, 1, 5000); // 1 second
                	}
                	else {
                        	usleep(SLEEPTIME);
                        	continue;
                	}
                	if(isset) fds.events = POLLIN;
                	if (error >= 1) break; // new connect comes
                	if (error == 0) continue; // Timeout, continue to wait

			//error =-1, error:

                	sprintf((char *)buf, "Error on poll(): %s/%d\n", strerror(errno), errno);
			debug("%s",buf);
                	if(errno != EAGAIN) break;
                	continue;
	     	} // for(;;) waiting for new connection...

		clntSock=accept(srvSock,(struct sockaddr *)&clntAddr, &addrLength);
		if( clntSock <0){
			sys_log(info_log, "%s\n","accept socket error in Service_Socks()");
			sys_log(info_log, "Error on accept(): %d:(%s)\n", errno,strerror(errno));
			return ;
		}
/*
		clnt=(struct sockaddr *)&clntAddr;
		debug("Accetp from:AF:%d, port:%d, ip:%s.\n", clnt->sin_family,ntohs(clnt->sin_port), inet_ntoa(clnt->sin_addr) );
		
*/

		socksArgs=(struct ThreadArgs *)malloc(sizeof(struct ThreadArgs));
		if(socksArgs ==NULL) 
		{
			debug("malloc error for socksArgs in socks.c:Service_Socks()\n");
			return ;

		};
		bzero((void *) socksArgs, sizeof(socksArgs));
        	socksArgs->version=version;
    		socksArgs->clntSock = clntSock;

    		res=pthread_create(&socksThreadID, NULL,HandleSocks, (void *) socksArgs) ;
    		if (res != 0)
    		{
		   sys_log(info_log, "Error Service_Socks() : pthread_create returns :%d(%s) ID:%ld \n",
				res,strerror(res), socksThreadID);
    		   return ;
    	        }
	}
	return ;
}

void * HandleSocks(void * args){
    int client;
    unsigned char version;
    unsigned long bytes;
    struct in_addr srcIP;
    //struct in6_addr srcIP6;
    //unsigned char srcIP[16];
    
    char strip[128];
    unsigned short srcPort;
    time_t tm_connect,tm_disconnect;
    struct tm * gtm;
    unsigned char v4or6;
    struct ThreadArgs * threadArgs;

    pthread_detach(pthread_self());	

    client = ((struct ThreadArgs *)args)->clntSock;	

    free(args);

    if(atomic_in(client,&version,sizeof(version)) != sizeof(version)) 
    {
	sys_log(info_log, "read() for protocol version failed (%s)",strerror(errno));
	close(client);
    }
    else if(version==SOCKS4_VERSION)
    {
	bytes=HandleSocks4(client); 

	/*
	//int get_remote_socket_info(int socket_fd, struct in_addr *ipAddress,int * port);
	if(0==get_remote_socket_info(client, &srcIP,&srcPort))
	{
		inet_ntop(AF_INET,&srcIP,strip,sizeof(struct in_addr));
        	access_log(acs_log,"sock4 : disconnect : %s : %d : %d\n",strip,ntohs(srcPort),bytes);
	}
	else
	{
		sys_log(info_log,"sock4: get_remote_socket_info erro");
	}
	close(client);
	*/
    }
    else if(version==SOCKS5_VERSION)
    {
	bytes=HandleSocks5(client);
        access_log(acs_log,"sock5 : disconnect : %s : %d : %d\n",strip,ntohs(srcPort),bytes);
	close(client);
    }

    pthread_exit(NULL);
}

int HandleSocks5(int clntSock){

    unsigned char nMethods, methods[255];
    unsigned char pdu[255];
    int result,bytes;
    int dstSocket;
    char dstHost[1024];
    char dstPort[64];
    struct socks5_request_pi request;
    int try_1, try_2;

  /***********************************
       +----+----------+----------+ 
       |VER | NMETHODS | METHODS  |
       +----+----------+----------+   
       | 1  |    1     | 1 to 255 | 
       +----+----------+----------+
  *************************************/ 
    // VER had been read, now read NMETHODS 

    ATOMIC_IN(clntSock, &nMethods,1,"Error on read NMETHODS in HandleSocks5");
    ATOMIC_IN(clntSock, methods, nMethods,"Error on Read METHODS");

    pdu[0]=SOCKS5_VERSION;
    pdu[1]=SOCKS5_METHOD_NONE;
    ATOMIC_OUT(clntSock,pdu,2,"Error on write method in HandleSocks5");

    result=ReadSocks5Request(clntSock, &request); 
    if(result<0) {
	sys_log(info_log,"ReadSocks5Request Error.\n");
	return -1;	
    }

    switch (request.command)
    {
	case	SOCKS_COMMAND_CONNECT:

	    if(request.atype ==SOCKS5_ATYPE_IPV4) 
	    {
		inet_ntop(AF_INET, (void*)&request.dst,dstHost,sizeof(dstHost));
	    }
	    else if(request.atype ==SOCKS5_ATYPE_IPV6) 
	    {
		inet_ntop(AF_INET6, (void*)&request.dst,dstHost,sizeof(dstHost));
	    }
	    else if(request.atype==SOCKS5_ATYPE_DOMAINNAME){
		memset(dstHost,0,sizeof(dstHost));	
		strncpy(dstHost,(void*)&request.dst,request.dstLen);
	    }

	    memset(dstPort,0,sizeof(dstPort));	
	    sprintf(dstPort,"%d",ntohs(request.port));
    	    debug("Got Socks5 request (%s:%s) .\n", dstHost, dstPort);
	    
	   /*
	    if(!strcmp(dstHost,"zh.wikipedia.org"))
	    {
		//"zh.wikipedia.org" can be connected successfully, be will be reset soon after connection established
		// tcp_connect return OK, but access is not allowed.
		// so, if I see zh.wikepedia.org, I will append .sixxs.org 
		strcat(dstHost,".sixxs.org");	
	    }
	    */
	    dstSocket=tcp_connect(dstHost, dstPort);  //non blocking , timeout=TIMEOUT
	    if(dstSocket <0)
            {
		
		//Reply error message	
    		result=WriteSocks5Response(clntSock, &request,SOCKS5_REP_HUNREACH); 
	        debug("I have replied Failed %s:%s\n", dstHost,dstPort);
		return -1;

	     }
	    else
	    {
	    	// Reply success message
    		result=WriteSocks5Response(clntSock, &request,SOCKS5_REP_SUCCEEDED); 
			
            	// Begin data relay ...
            	bytes=shuffle_bytes(clntSock,dstSocket);
		
            	close(dstSocket);	
	     }
		
	break;

	case	SOCKS_COMMAND_BIND:
		//This COMMAND is used to handle FTP reverse Connection

	break;

	case	SOCKS_COMMAND_UDP_ASSOC:

	break;
    }

    return 0;
}
/********************************************************************

        +----+-----+-------+------+----------+----------+
        |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
        +----+-----+-------+------+----------+----------+
        | 1  |  1  | X'00' |  1   | Variable |    2     |
        +----+-----+-------+------+----------+----------+
**********************************************************************/
int ReadSocks5Request(int clntSock, struct socks5_request_pi *request)
{
        unsigned char length;
	if(request==NULL) return -1;
	
	ATOMIC_IN(clntSock, &request->version,1,"Error on read version in ReadSocks5Request");	
	ATOMIC_IN(clntSock, &request->command,1,"Error on read command in ReadSocks5Request");	
	ATOMIC_IN(clntSock, &request->reserved,1,"Error on read reserved in ReadSocks5Request");	
	ATOMIC_IN(clntSock, &request->atype,1,"Error on read atype in ReadSocks5Request");	
	switch(request->atype)
	{
	    case SOCKS5_ATYPE_IPV4: 
		 ATOMIC_IN(clntSock, &request->dst,4,"Error on read DST.ADDR(IPv4) in ReadSocks5Request"); 
		 request->dstLen=4;
	    break;
	    case SOCKS5_ATYPE_DOMAINNAME: 
		 ATOMIC_IN(clntSock, &request->dstLen,1,"Error on read Length inDST.ADDR(DomainName) in ReadSocks5Request"); 
		 ATOMIC_IN(clntSock, &request->dst,request->dstLen,"Error on read Length inDST.ADDR(DomainName) in ReadSocks5Request"); 
	    break;
	    case SOCKS5_ATYPE_IPV6:
		 ATOMIC_IN(clntSock, &request->dst,16,"Error on read DST.ADDR(IPv6) in ReadSocks5Request"); 
		 request->dstLen=16;
	    break;
	}
	ATOMIC_IN(clntSock, &request->port,2,"Error on read port in ReadSocks5Request");	
	return 0;	
}
/*******************************************

        +----+-----+-------+------+----------+----------+
        |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
        +----+-----+-------+------+----------+----------+
        | 1  |  1  | X'00' |  1   | Variable |    2     |
        +----+-----+-------+------+----------+----------+
*********************************************/
int WriteSocks5Response(int clntSock, struct socks5_request_pi *request,unsigned char reply_code) 
{

   unsigned char *pdu, *ptr;
   int length;

   length=6+request->dstLen;
      
   if(request->atype==SOCKS5_ATYPE_DOMAINNAME)
   {
	length++;  //The first byte is the length of the domain name
   }   
   pdu=(unsigned char *) malloc(length); //

   
   ptr=pdu;
   *ptr=SOCKS5_VERSION;
   ptr++;  // VER :1
   *ptr=reply_code;
   ptr++;  // REP:2
   
   *ptr=0;
    ptr++; //RESERVE:3

    *ptr=request->atype;
    ptr++;  //ATYPE:4
    
    if(request->atype==SOCKS5_ATYPE_DOMAINNAME)
    {
	*ptr=request->dstLen;
	ptr++; // lenght of domain name :5
    }
    memcpy(ptr, request->dst, request->dstLen);
    ptr+=request->dstLen;

    memcpy(ptr,&request->port,2);
    ptr+=2;

    ATOMIC_OUT(clntSock,pdu,length,"Error on write response in WriteSocks5Response");
    
   return 0;
}

int ReadSocks4RequestWithoutVN(int client, struct socks4_request_tunnet *request)
{
 /*****************************************************
		+----+----+----+----+----+----+----+----+----+----+....+----+
		| VN | CD | DSTPORT |      DSTIP        | USERID       |NULL|
		+----+----+----+----+----+----+----+----+----+----+....+----+
		   1    1      2              4              variable  

 ********************************************************/
    char * ptr, ch, userNameHops[MAX_USERNAME];
    //int i;

    if(request==NULL) return -1;
    memset(request,0, sizeof(request));

    ATOMIC_IN(client, &request->command,1, "Read Sockes4 Request command error in socks.c:ReadSocks4RequestWithoutVN()\n");
    ATOMIC_IN(client, &request->port,2, "Read Sockes4 Request  DSTPORT error in socks.c:ReadSocks4RequestWithoutVN()\n");
    ATOMIC_IN(client, &request->addr,4, "Read Sockes4 Request  DSTIP error in socks.c:ReadSocks4RequestWithoutVN()\n");

    ptr=userNameHops;
    do {
        atomic_in(client,&ch,sizeof(ch));
        *ptr=ch;
        ptr++;
	//i++;
    } while(ch);

    getUserHops(userNameHops,request->username, &request->hops);

    return 0;
}
unsigned long  HandleSocks4(int client )   //, struct sockaddr_storage *clntAddr)
{

    unsigned char command;
    unsigned long destAddr;
    unsigned short destPort;

    unsigned long srcIP;
    time_t tm;
    struct tm *gtm;

    int c; char ch;
    char userName[MAX_USERNAME],userNameHops[MAX_USERNAME+3],*ptr;

    struct sockaddr_in sai, remote_addr;
    struct sockaddr  clientAddr;
    struct sockaddr_in6 *clientAddr6;
    int remote_port,src_port;
    int status;
    int sock;
    unsigned long bytes; // accounting how many bytes I relayed; 
   
    //struct socks4_request request;	
    struct socks4_request_tunnet request;	
    struct socks4_response response;	
    int j ,hops;
    struct in_addr tip ,src_addr;
    char strip[128],strip_s[128];
    int version=4;
    int srcPort;
    int addrLen;
    struct sockaddr_in clntAddr;

    struct node_item *p_clt, *p_svr;

    ReadSocks4RequestWithoutVN(client, &request);

    addrLen=sizeof(struct sockaddr);

    status=getpeername(client,(struct sockaddr *)&clntAddr,&addrLen);
    if( status)
    {
	debug("Error on getpeername in HandleSocks4:socks.c, client=%d\n",client);
	return -1;	
     }
    srcIP=clntAddr.sin_addr.s_addr;
    //inet_ntop(AF_INET,&srcIP,strip_s,sizeof(strip_s));
    strcpy(strip_s, inet_ntoa(clntAddr.sin_addr));

    strcpy(userName,request.username);

    hops=request.hops;

    command = request.command;
    destAddr = request.addr;
    destPort = request.port;
    tip.s_addr=destAddr;

    inet_ntop(AF_INET,&destAddr,strip,sizeof(strip));
    inet_ntop(AF_INET,&clntAddr.sin_addr.s_addr,strip_s,sizeof(strip_s));

    debug("Get SOCKS4 Request from %s:[ VN:%d CMD:%d DestPort:%d DestIP:%s UserName:%s Hops:%d\n",
	 strip_s,version,command, ntohs(destPort),strip,userName, hops); 
    access_log(acs_log,"sock4 : connect : %s : %s : %d : %s : %d\n",		
	userName,strip_s,ntohs(srcPort),strip,ntohs(destPort));


    // add acl here ...
/*	
    if(ACTION_PERMIT !=acl_lookup4(&acl4,src_addr.s_addr)){
        debug("source Address not permited !\n");
	response.version = SOCKS4_VERSION;
        response.reply = SOCKS4_REP_REJECTED;
        memcpy(&response.port, &destPort, sizeof(destPort));
        memcpy(&response.port, &destAddr, sizeof(destAddr));
        atomic_out(client,&response,sizeof(response));
        return 0;
    }
*/

    // check loops ...

    if(hops > MAX_HOPS ){
	debug("MAX_HOPS(%d) exceeded , reply error\n");		
	response.version = SOCKS4_VERSION;
        response.reply = SOCKS4_REP_HOPS_EXCEED;
	memcpy(&response.port, &destPort, sizeof(destPort));
	memcpy(&response.port, &destAddr, sizeof(destAddr));
        ATOMIC_OUT(client,&response,sizeof(response),"Error when reply MAX_HOPS in HandleSocks4 : socks.c\n");
        //atomic_out(client,&response,sizeof(response));	
	//return 0;
    }
    

    // handle the command 
    switch(command){
	case SOCKS_COMMAND_CONNECT:
	{
	    //status=connect(sock, (struct sockaddr*)&sai, sizeof(sai));

	    int clientIsNbr, serverIsNbr,nextNodeID;
	    status=p2p_connect(&sock,srcIP,destAddr, destPort,hops,&nextNodeID);
		 /* status ==0 if success , otherwise status ==-1; */

	     /** Notice: destAddr and destPort are both in network order **/

	    //reply 
	    response.version = SOCKS4_VERSION;
	    if(status!=0) { // error
		response.reply = SOCKS4_REP_REJECTED;
            }
	    else{ //OK
		response.reply = SOCKS4_REP_SUCCEEDED;
		j = sizeof(sai);
		//getsockname(sock, (struct sockaddr *)(&sai),&j);
		getpeername(sock, (struct sockaddr *)(&sai),&j);

		response.addr = sai.sin_addr.s_addr; //remote_addr;
		response.port = sai.sin_port; //remote_port;
            }
	    atomic_out(client,&response,sizeof(response));		

	    if(status) return 0; // error

/*
	    //2008-05-17

		p_clt=neighbor_lookup_byName(&neighbors, userName);	
		if(p_clt) 
                    clientIsNbr=1 ;
                else
		    clientIsNbr=0; 	
		//	p_svr=neighbor_lookup_byIP(&neighbors,response.addr);	
		//if(p_svr) 
		if(nextNodeID ==0)  // connect from itself
                      serverIsNbr=0 ;
                else
		    serverIsNbr=1; 	
		
		if( clientIsNbr ^ serverIsNbr) 
		{
		  // if one of client or server is neighbor, encode it.
	          	  
    		  debug("client:%s,clientIsNbr:%d; server:%s, serverIsNbr:%d, encode it. \n",
			userName,clientIsNbr,strip,serverIsNbr);
	    	  bytes=shuffle_bytes_encode(client,sock);
		}
		else
		{
		  //if client and server are both neighbor node , or neither one is neighbor node
    		  debug("client:%s,clientIsNbr:%d; server:%s, serverIsNbr:%d, exchange directyl. \n",
			userName,clientIsNbr,strip,serverIsNbr);
	    	  bytes=shuffle_bytes(client,sock);
		}

	    //end of 2008-05-17
*/
	    bytes=shuffle_bytes(client,sock);

	    close(sock);
    	    access_log(acs_log,"sock4 : connect : %s : %s : %d : %s : %d\n",		
		                userName,strip_s,ntohs(srcPort),strip,ntohs(destPort));
	    return bytes;

	}   //case CONNECT
	break;

	case SOCKS_COMMAND_BIND:
   	{
		int sockServer,j;

		debug("Handle BIND ...\n");

		sock=socket(AF_INET, SOCK_STREAM,0);
		sai.sin_addr.s_addr=INADDR_ANY;
		sai.sin_family=AF_INET;
		sai.sin_port=htons(destPort);

		status=bind(sock,(struct sockaddr *)(&sai),sizeof(sai));

		if(status == 0) {
			j = sizeof(sai);
			getsockname(sock, (struct sockaddr *)(&sai),&j);
			//remote_addr = sai.sin_addr.s_addr;
			//remote_port = sai.sin_port;
			response.addr = sai.sin_addr.s_addr; //remote_addr;
			response.port = sai.sin_port; //remote_port;
		}
		else{
			sys_log(info_log , "error on bind (HandleSocks4)\n");
		}
		response.version = SOCKS4_VERSION;
		response.reply = status?91:90;
		atomic_out(client,&response,sizeof(response));
		if(status) return -1;

		listen(sock,1);
		j = sizeof(sai);
		sockServer=accept(sock,(struct sockaddr *)(&sai),&j);
		debug("BIND: accepted \n");
		if(sockServer !=-1){
			status=0;
			//remote_addr = sai.sin_addr.s_addr;
			//remote_port = sai.sin_port;
			response.addr = sai.sin_addr.s_addr; //remote_addr;
			response.port = sai.sin_port; //remote_port;
		}	
		else{
			status=-1;
			sys_log(info_log, "accept error(HandleSocks4, BIND\n");
		}
		response.version = SOCKS4_VERSION;
		response.reply = status?91:90;
		//response.addr = remote_addr;
		//response.port = remote_port;
		atomic_out(client,&response,sizeof(response));	
		
		if(status) return -1;
	    	bytes=shuffle_bytes(client,sock);
	    	return bytes;

	}// case BIND
	break;
		
    }   // switch
}


/*************************************************************************** 
**  API for client application who want connect (destAddr,destPort) via socks4(nbr_ip, nbr_port)
**  if success, returns 0, *sock will be the connected socket
**  otherwise,  returns -1, *sock is undefined.
****************************************************************************/
/********** 
***Note: nbr_ip :  network order
**       nbr_port: network order
**       destAddr: network order
**       destPort: network order
******************************************** ********************/
/* if success, return 0, and *sock is the new socket;
   else return -1;
*/
int connect_socks4(int *sock,in_addr_t nbr_ip,unsigned short nbr_port,
        char *userName,in_addr_t destAddr, unsigned short destPort)
{
	// socket s , saddr are used for connect socks server;
	int s;
	int res;
	// sai used for store destination address and port
	struct sockaddr_in saddr;
	char ip_str[128];

	s = socket(AF_INET,SOCK_STREAM,0);
	if(s <0) {
		sys_log(info_log, "socket error (connect_socks4)\n");
		return -1;
	}
	saddr.sin_family=AF_INET;
	saddr.sin_addr.s_addr=nbr_ip; //htonl(nbr_ip);
        saddr.sin_port =nbr_port;

        //connect socks server
        res= connect_nonb(s, (struct sockaddr *)&saddr, sizeof(saddr),&timeout);
        if ( res <0 ) {
	    inet_ntop(AF_INET, &nbr_ip, ip_str, sizeof(ip_str));
	    sys_log(info_log, "Timeout when connect neighbor(%s)\n",ip_str);
            close (s);
            return -1;
        }

	//Now, socks server connected, neigotiate with it ... 
	res=begin_socks4(s, destAddr, destPort, userName);	
	if(res !=0){
		inet_ntop(AF_INET, &destAddr, ip_str,sizeof(ip_str));
	        sys_log(info_log, "Error on begin_socks4(%s,%d,%s)\n",
			ip_str,ntohs(destPort),userName);
		close(s);
		return -1;	
	} 
	*sock =s;
	return 0; //OK
}

/***************************************************
** SOCKS4 neigotiation, used before SOCKS4 communication
** 
Send:
	+----+----+----+----+----+----+----+----+----+----+....+----+
	| VN | CD | DSTPORT |      DSTIP        | USERID       |NULL|
	+----+----+----+----+----+----+----+----+----+----+....+----+
	   1    1      2              4           variable       1

Recv:
	
	+----+----+----+----+----+----+----+----+
	| VN | CD | DSTPORT |      DSTIP        |
	+----+----+----+----+----+----+----+----+
 	   1    1      2              4

destPort and destAddr are host address order
***************************************************/
int begin_socks4(int sock, in_addr_t destAddr, unsigned short destPort, char *userName)
{
	struct socks4_request request;   
    	struct socks4_response response;
    	unsigned char buf[256], *ptr;
	unsigned char version, command, response_code;
	unsigned long dstIP;
	unsigned short dstPort;


    /* make connect request packet
       protocol v4:
         VN:1, CD:1, PORT:2, ADDR:4, USER:n, NULL:1
       protocol v4a:
         VN:1, CD:1, PORT:2, DUMMY:4, USER:n, NULL:1, HOSTNAME:n, NULL:1
    */
	version=SOCKS4_VERSION;
	command=SOCKS_COMMAND_CONNECT;
	dstPort=destPort;
	dstIP=  destAddr;

	atomic_out(sock,&version,1);
	atomic_out(sock,&command,1);
	atomic_out(sock,&dstPort,2);
	atomic_out(sock,&dstIP,4);
	strcpy(buf,userName);
	buf[strlen(userName)]='\0';
	atomic_out(sock,buf, strlen(userName)+1);	

	memset(buf, 0, 8);
    	if(8!=atomic_in(sock, buf, 8 )){
        	sys_log(info_log,"error read response from socks server(begin_socks4))\n ");   
        	return -1;
     	}
	response_code=buf[1];
	if ( (response_code != SOCKS4_REP_SUCCEEDED) ) { 
        	sys_log(info_log,"Got error response:%d(%s).\n", (int)buf[1],
			lookup_code(socks4_code,response_code) );
    		return -1;
    	}
	return 0;
}


